package core;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

import util.NameSet;
import util.NamedSet;
import util.Reflection;
import util.ResourceManager;
import core.behaviors.Behavior;
import core.units.Unit;

/**
 * Bind triggers to behaviors
 * 
 * The game controller provides a means to allow the user to change the
 * state of units in the game.  The game controller will map triggers to
 * behavior-unit combinations.  When the trigger is fired then the behavior
 * is stepped through once.
 * 
 * Note that the current game controller supports only 1 behavior-unit pair
 * to a given trigger.
 * 
 * @version 1.4
 * @author Alexander Schearer <aas11@duke.edu>
 */
public class GameController {

	private Level myLevel;

	private NameSet<NamedSet<Behavior>> myResponses;

	private HashMap<String, Unit> myResponders;

	private ResourceManager myResources;

	private Queue<Behavior> trash_buffer;

	private static GameController singleton;

	public GameController() {
		myLevel = null;
		myResponses = new NameSet<NamedSet<Behavior>>();
		myResponders = new HashMap<String, Unit>();
		myResources = new ResourceManager(this);
		trash_buffer = new LinkedList<Behavior>();
		singleton = this;
	}

	public boolean bindKey(String key, String behavior, String unit) {
		try {
			Behavior b = (Behavior) Reflection.createInstance(myResources
					.getString(behavior), behavior);
			bindKey(key, b, unit);
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
	public boolean bindKey(String key, Behavior behavior, String unit) {
		try {
			NamedSet<Behavior> responses = myResponses.get(key);
			if (responses == null)
				responses = new NamedSet<Behavior>(key);
			responses.add(behavior);
			myResponses.add(responses);
			Unit u = myLevel.get(unit);
			myResponders.put(key, u);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	public void trigger(String key) {
		try {
			NamedSet<Behavior> responses = myResponses.get(key);
			Unit u = myResponders.get(key);
			for (Behavior b : responses) {
				b.step(u);
			}
		} catch (Exception e) {
			return;
		}
	}
	
	public void setLevel(Level l) {
		myLevel = l;
	}
	
	public static GameController getSingleton()
	{
		if (singleton == null)
			singleton = new GameController();
		return singleton;
	}

}
